package com.dynamic.mybatis.bootstrap.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dynamic.mybatis.bootstrap.entity.DataSourceEntity;
import com.dynamic.mybatis.bootstrap.entity.MappedStatementEntity;
import com.dynamic.mybatis.bootstrap.mapper.DataSourceMapper;
import com.dynamic.mybatis.bootstrap.mapper.MappedStatementMapper;
import com.dynamic.mybatis.core.datasource.DataSourceProperty;
import com.dynamic.mybatis.core.metadata.DynamicMappedStatement;
import com.dynamic.mybatis.core.metadata.MappedStatementMetaField;
import com.dynamic.mybatis.core.parser.NamespaceHelper;
import com.dynamic.mybatis.core.session.DynamicSqlSessionTemplate;
import com.dynamic.mybatis.core.utils.BeanUtils;
import com.dynamic.mybatis.core.utils.CollectionUtils;
import com.google.common.reflect.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 从外部加载 DynamicDataSource 和  DynamicMappedStatement
 */
@Component
public class MappedStatementInitializeRunner implements ApplicationRunner {

    @Autowired
    @Lazy
    DynamicSqlSessionTemplate dynamicSqlSessionTemplate;
    @Autowired
    @Lazy
    private DataSourceMapper dataSourceMapper;
    @Autowired
    @Lazy
    private MappedStatementMapper mappedStatementMapper;

    @Override
    public void run(ApplicationArguments args) {
        new Thread(() -> {
            initDatasource();
            initMappedStatement();
        }).start();
    }


    public void initMappedStatement() {
        LambdaQueryWrapper<MappedStatementEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MappedStatementEntity::getIsDeleted, 0);
        List<MappedStatementEntity> dms = mappedStatementMapper.selectList(wrapper);
        List<DynamicMappedStatement> list = dms.stream().map(ms ->
                new DynamicMappedStatement().toBuilder()
                        .setUid(String.valueOf(ms.getId()))
                        .setShortId(ms.getCode())
                        .setName(ms.getName())
                        .setCommandType(ms.getCommandType())
                        .setNamespace(ms.getNamespace())
                        .setEnable(ms.getStatus() != null && ms.getStatus() == 1)
                        .setTables(JSON.parseObject(ms.getTables(), new TypeToken<List<String>>() {
                        }.getType()))
                        .setSqlStatement(ms.getSqlStatement())
                        .setResultType(ms.getReturnType())
                        .setReturnType(ms.getReturnType())
                        .setDynamicDataSourceKeys(CollectionUtils.toArray(JSON.parseObject(ms.getDataSourceUniqueCodes(), new TypeToken<List<String>>() {
                        }.getType()), String[].class))
                        .setInputParameter(JSON.parseArray(ms.getInputParameter(), MappedStatementMetaField.class, JSONReader.Feature.SupportClassForName))
                        .setOutputParameter(JSON.parseArray(ms.getOutputParameter(), MappedStatementMetaField.class, JSONReader.Feature.SupportClassForName))
                        .setCreateTime(ms.getCreateTime())
                        .setCreateBy(ms.getCreateBy())
                        .setUpdateTime(ms.getUpdateTime())
                        .setUpdateBy(ms.getUpdateBy())
                        .builder()
        ).collect(Collectors.toList());
        dynamicSqlSessionTemplate.getDynamicMappedStatementHelper().addParseDynamicMappedStatement(list);
    }

    public void initDatasource() {
        LambdaQueryWrapper<DataSourceEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DataSourceEntity::getIsDeleted, 0);
        List<DataSourceEntity> dds = dataSourceMapper.selectList(wrapper);

        dds.stream().forEach(ds -> {
            String key = NamespaceHelper.getIdentity(ds.getNamespace(), ds.getCode());
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setUrl(ds.getUrl());
            dataSource.setUsername(ds.getUsername());
            dataSource.setPassword(ds.getPassword());
            dataSource.setDriverClassName(ds.getDriverClass());
            DataSourceProperty property = BeanUtils.copy(ds, new DataSourceProperty());
            property.setUid(String.valueOf(ds.getId()));
            Map attributes = JSON.parseObject(ds.getAttributes());

            dynamicSqlSessionTemplate.addDataSource(key, dataSource, property, attributes);
        });
    }
}
